﻿using System;
using System.Configuration;
using NCommet.Core.Agents;
using NCommet.Core.Services;

namespace NCommet.Core.Configuration
{
    /// <summary>
    /// <c>Configurator</c> automatically configures <see cref="NCommet.Core.Services.NCommetContainer"/>
    /// from the application configuration file. The configuration section loaded must be named "ncommet"
    /// and its type is <see cref="NCommetCfgSection" />.
    /// </summary>
    public static class Configurator
    {
        /// <summary>
        /// Configures <see cref="NCommet.Core.Services.NCommetContainer" />, adding modules,
        /// loading concrete implementations and assigning them to their respective interface properties.
        /// </summary>
        public static void Configure()
        {
            NCommetCfgSection n = (NCommetCfgSection)ConfigurationManager.GetSection("ncommet");
            if (n == null)
                throw new Exception("ncommet section was not found");

            if (n.Modules != null)
                foreach (ModuleCfgElement m in n.Modules)
                {
                    IModule module = LoadObject<IModule>(m.Type, true);
                    NCommetContainer.Instance.AddModule(module);
                }

            NCommetContainer.Instance.Persister = LoadObject<IPersister>(n.Persister, false);
            NCommetContainer.Instance.Sorter = LoadObject<ISorter>(n.Sorter, false);
            NCommetContainer.Instance.Searcher = LoadObject<ISearcher>(n.Searcher, false);
            NCommetContainer.Instance.TypedTreeValidator = LoadObject<ITypedTreeValidator>(n.TypedTreeValidator, false);
            NCommetContainer.Instance.DaoEventsSink = LoadObject<IDaoEventsSink>(n.DaoEventsSink, false);
            NCommetContainer.Instance.WhoAmI = LoadObject<IWhoAmI>(n.WhoAmI, false);
            NCommetContainer.Instance.AuthorizationManager = LoadObject<IAuthorizationManager>(n.AuthorizationManager, false);
        }

        private static T LoadObject<T>(string name, bool throwOnNotDeclared)
        {
            if (string.IsNullOrEmpty(name))
            {
                if (throwOnNotDeclared)
                    throw new Exception("Not declared " + name);
                else return default(T);
            }
            Type t = Type.GetType(name);
            if (t == null)
                throw new Exception("Could not load " + name);
            return (T)t.GetConstructor(Type.EmptyTypes).Invoke(null);
        }
    }
}
